<?php
class DateRangeField extends FormField {
	/**
	 * @config
	 * @var array
	 */
	private static $default_config = array(
		'jslocale' => null,
		'dateformat' => null,
		'datavalueformat' => 'yyyy-MM-dd'
	);
	
	/**
	 * @var array Maps values from {@link i18n::$all_locales} to 
	 * localizations existing in jQuery UI.
	 */
	private static $locale_map = array(
		'en_GB' => 'en-GB',
		'en_US' => 'en', 
		'en_NZ' => 'en-GB', 
		'fr_CH' => 'fr',
		'pt_BR' => 'pt-BR',
		'sr_SR' => 'sr-SR',
		'zh_CN' => 'zh-CN',
		'zh_HK' => 'zh-HK',
		'zh_TW' => 'zh-TW',
	);
	
	/**
	 * @var array
	 */
	protected $config;
	
	/**
	 * @var String
	 */
	protected $locale = null;
	
	/**
	 * @var Zend_Date Just set if the date is valid.
	 * {@link $value} will always be set to aid validation,
	 * and might contain invalid values.
	 */
	protected $valueStartObj = null;
	
	/**
	 * @var Zend_Date Just set if the date is valid.
	 * {@link $value} will always be set to aid validation,
	 * and might contain invalid values.
	 */
	protected $valueEndObj = null;

	public function __construct($name, $title = null, $value = '') {
		Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js');
		Requirements::javascript(THIRDPARTY_DIR . '/jquery-livequery/jquery.livequery.js');
		Requirements::css(THIRDPARTY_DIR . '/jquery-ui-themes/smoothness/jquery-ui.css');
		Requirements::javascript(FRAMEWORK_DIR . '/thirdparty/jquery-ui/jquery-ui.js');
		Requirements::javascript('general/thirdparty/jquery-daterange/src/jquery.daterange.js');
        Requirements::javascript('general/javascript/DateRangeField.min.js');
		
		if(!$this->locale) {
			$this->locale = i18n::get_locale();
		}
		
		$this->config = $this->config()->default_config;
		if(!$this->getConfig('dateformat')) {
			$this->setConfig('dateformat', i18n::get_date_format());
		}
		
		foreach ($this->config()->default_config AS $defaultK => $defaultV) {
			if ($defaultV) {
				if ($defaultK=='locale')
					$this->locale = $defaultV;
				else
					$this->setConfig($defaultK, $defaultV);
			}
		}
		
		parent::__construct($name, $title, $value);
	}
	
	public function Field($properties = array()) {
		$lang = $this->getLang();
		$localeFile = THIRDPARTY_DIR . "/jquery-ui/datepicker/i18n/jquery.ui.datepicker-{$lang}.js";
		if (file_exists(Director::baseFolder() . '/' .$localeFile)){
			Requirements::javascript($localeFile);
		}
		
		$config = array(
			'isoDateformat' => $this->getConfig('dateformat'),
			'jquerydateformat' => DateField_View_JQuery::convert_iso_to_jquery_format($this->getConfig('dateformat'))
		);

		// Add other jQuery UI specific, namespaced options (only serializable, no callbacks etc.)
		// TODO Move to DateField_View_jQuery once we have a properly extensible HTML5 attribute system for FormField
		$jqueryUIConfig = array();
		foreach($this->getConfig() as $k => $v) {
			if(preg_match('/^jQueryUI\.(.*)/', $k, $matches)) $jqueryUIConfig[$matches[1]] = $v;
		}
		if ($jqueryUIConfig)
			$config['jqueryuiconfig'] =  Convert::array2json(array_filter($jqueryUIConfig));
		$config = array_filter($config);
		foreach($config as $k => $v) $this->setAttribute('data-' . $k, $v);
		
		return parent::Field();
	}

	function getAttributes() {
        return array_merge(
            parent::getAttributes(), array(
            	'rel' => 'daterange',
                'autocomplete' => 'off'
            )
        );
    }

	public function Type() {
		return 'daterange text';
	}
	
	/**
	 * Sets the internal value to ISO date format.
	 * 
	 * @param String|Array $val 
	 */
	public function setValue($val) {
		$locale = new Zend_Locale($this->locale);
		
		if(empty($val)) {
			$this->value = null;
			$this->valueStartObj = null;
			$this->valueEndObj = null;
		} else {
			// Setting in corect locale.
			// Caution: Its important to have this check *before* the ISO date fallback,
			// as some dates are falsely detected as ISO by isDate(), e.g. '03/04/03'
			// (en_NZ for 3rd of April, definetly not yyyy-MM-dd)
			if(is_array($val)){
				$start = isset($val['_Start']) ? $val['_Start'] : '';
				$end = isset($val['_End']) ? $val['_End'] : $start;
			} else {
				$date = explode(' - ', $val);
				$start = $end = $date[0];
				if(isset($date[1])){
					$end = $date[1];
				}
			}
			if(!empty($start) && Zend_Date::isDate($start, $this->getConfig('dateformat'), $locale)) {
				$this->valueStartObj = new Zend_Date($start, $this->getConfig('dateformat'), $locale);
				$this->value = $this->valueStartObj->get($this->getConfig('dateformat'), $locale);
				if(!empty($end) && Zend_Date::isDate($end, $this->getConfig('dateformat'), $locale)) {
					$this->valueEndObj = new Zend_Date($end, $this->getConfig('dateformat'), $locale);
					$this->value .= ' - '.$this->valueEndObj->get($this->getConfig('dateformat'), $locale);
				} else {
					$this->valueEndObj = new Zend_Date($start, $this->getConfig('dateformat'), $locale);
					$this->value .= ' - '.$this->valueEndObj->get($this->getConfig('dateformat'), $locale);
				}
			}
			// load ISO date from database (usually through Form->loadDataForm())
			else if(!empty($start) && Zend_Date::isDate($start, $this->getConfig('datavalueformat'))) {
				$this->valueStartObj = new Zend_Date($start, $this->getConfig('datavalueformat'));
				$this->value = $this->valueStartObj->get($this->getConfig('datavalueformat'), $locale);
				if(!empty($end) && Zend_Date::isDate($end, $this->getConfig('datavalueformat'))) {
					$this->valueEndObj = new Zend_Date($end, $this->getConfig('datavalueformat'));
					$this->value .= ' - '.$this->valueEndObj->get($this->getConfig('datavalueformat'), $locale);
				} else {
					$this->valueEndObj = new Zend_Date($start, $this->getConfig('datavalueformat'));
					$this->value .= ' - '.$this->valueEndObj->get($this->getConfig('datavalueformat'), $locale);
				}
			}
			else {
				$this->value = $val;
				$this->valueStartObj = null;
				$this->valueEndObj = null;
			}
		}

		return $this;
	}
	
	/**
	 * @return String ISO 8601 date, suitable for insertion into database
	 */
	public function dataValue() {
		if($this->valueStartObj) {
			$val['_Start'] = $val['_End'] = $this->valueStartObj->toString($this->getConfig('datavalueformat'));
			if($this->valueEndObj){
				$val['_End'] = $this->valueEndObj->toString($this->getConfig('datavalueformat'));
			}
			return $val;
		} else {
			return null;
		}
	}
	
	/**
	 * @return Boolean
	 */
	public function validate($validator) {
		$valid = true;
		
		// Don't validate empty fields
		if(empty($this->value)) return true;

		// date format
		$val = explode(' - ', $this->value);
		$start = $val[0];
		if(isset($val[1])){
			$end = $val[1];
		} else {
			$end = $val[0];
		}
		$valid = (Zend_Date::isDate($start, $this->getConfig('dateformat'), $this->locale) && Zend_Date::isDate($end, $this->getConfig('dateformat'), $this->locale));

		if(!$valid) {
			$validator->validationError(
				$this->name, 
				_t(
					'DateRangeField.VALIDDATEFORMAT2', "Please enter a valid date format ({format})", 
					array('format' => $this->getConfig('dateformat'))
				), 
				"validation", 
				false
			);
			return false;
		} else if($this->valueEndObj->isEarlier($this->valueStartObj)){
			$validator->validationError(
				$this->name, 
				_t(
					'DateRangeField.VALIDDATEFORMAT2', "Please enter a valid date range"
				), 
				"validation", 
				false
			);
		}
		
		return true;
	}
	
	/**
	 * Determines which language to use for jQuery UI, which
	 * can be different from the value set in i18n.
	 * 
	 * @return String
	 */
	protected function getLang() {
		$locale = $this->getLocale();
		$map = $this->config()->locale_map;
		if($this->getConfig('jslocale')) {
			// Undocumented config property for now, might move to the jQuery view helper
			$lang = $this->getConfig('jslocale');
		} else if(array_key_exists($locale, $map)) {
			// Specialized mapping for combined lang properties
			$lang = $map[$locale];
		} else {
			// Fall back to default lang (meaning "en_US" turns into "en")
			$lang = i18n::get_lang_from_locale($locale);
		}
		
		return $lang;
	}
	
	/**
	 * @return string
	 */
	public function getLocale() {
		return $this->locale;
	}
	
	/**
	 * Caution: Will not update the 'dateformat' config value.
	 * 
	 * @param String $locale
	 */
	public function setLocale($locale) {
		$this->locale = $locale;
		return $this;
	}
	
	/**
	 * @param string $name
	 * @param mixed $val
	 */
	public function setConfig($name, $val) {
		$this->config[$name] = $val;
		return $this;
	}
	
	/**
	 * @param String $name Optional, returns the whole configuration array if empty
	 * @return mixed|array
	 */
	public function getConfig($name = null) {
		if($name) {
			return isset($this->config[$name]) ? $this->config[$name] : null;
		} else {
			return $this->config;
		}
	}
}
?>
